package main

import (
	"fmt"
	"io"
	"net"
	"os"
	"strings"
	"time"
)

// 编写新版本的客户端和服务器 (client1.go / server1.go)：

// 增加一个检查错误的函数 checkError(error)；讨论如下方案的利弊：为什么这个重构可能并没有那么理想？看看在 示例 15.14 中它是如何被解决的
// 使客户端可以通过发送一条命令 SH 来关闭服务器
// 让服务器可以保存已经连接的客户端列表（他们的名字）；当客户端发送 WHO 指令的时候，服务器将显示如下列表：

// This is the client list: 1:active, 0=inactive
// User IVO is 1
// User MARC is 1
// User CHRIS is 1

// 注意：当服务器运行的时候，你无法编译/连接同一个目录下的源码来产生一个新的版本，因为 server.exe 正在被操作系统使用而无法被替换成新的版本。

type client struct {
	active int
	chAct  chan int
}

var users = make(map[string]*client)

func main() {
	fmt.Println("server start...")
	address := "localhost"
	port := "50000"

	// list := make(map[string]int)

	// 监听
	listener, err := net.Listen("tcp", address+":"+port)
	if err != nil {
		fmt.Println("Error listen:", err)
		return
	}

	for {
		conn, err := listener.Accept()
		if err == io.EOF {
			continue
		}
		checkError(err)
		go doServerStuff(conn)
	}
}

func checkError(err error) {
	if err != nil {
		panic("Error Accepting: " + err.Error())
	}
}

func doServerStuff(conn net.Conn) {
	var buf []byte
	var err error

	for {
		buf = make([]byte, 512)
		_, err = conn.Read(buf)
		checkError(err)
		str := string(buf)
		// 关闭服务器
		if strings.Contains(str, ": SH") {
			fmt.Println("server shutting down.")
			os.Exit(0)
		}
		// 列出users
		if strings.Contains(str, ": WHO") {
			fmt.Println("This is the client list: 1:active, 0=inactive")
			for name, client := range users {
				fmt.Println("USER", name, "is", client.active)
			}
			continue
		}

		// 取出says前面的字符串作为user name
		ix := strings.Index(str, "says")
		userName := str[:ix-1]
		if _, ok := users[userName]; !ok {
			users[userName] = &client{1, make(chan int, 1)}
		} else {
			users[userName].active = 1
			users[userName].chAct <- 1
		}
		// 30秒后设置为不活跃
		go func(name string) {
			usr := users[name]
			chAfter := time.After(30e9)

			select {
			case <-chAfter:
				usr.active = 0
			// 再次登陆则关闭该协程
			case <-usr.chAct:
			}
			return
		}(userName)

		// 输出
		fmt.Printf("Received data: --%v--\n", str)

	}
}
